home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / packet / p_aa4re / mbb35src / 8250int.asm < prev    next >
Encoding:
Assembly Source File  |  1990-10-14  |  23.2 KB  |  500 lines

  1. ;==========================================================================;
  2. ; 8250 and QuardRam Quadport Interrupt handler                             ;
  3. ;                                                                          ;
  4. ;   Copyright 1983 by William E. Westfield.  All rights reserved.          ;
  5. ;   Copyright 1986, 1988,1990 by H. Roy Engehausen.  All rights reserved.  ;
  6. ;   This software may be freely distributed and used, but it may not       ;
  7. ;   under any circumstances be sold by anyone other than the author.       ;
  8. ;   It may be distributed by a commercial company as long as it is         ;
  9. ;   for no cost.                                                           ;
  10. ;==========================================================================;
  11.  
  12.   IF present_qrqp OR present_4apc
  13.  
  14.         CMP     chip[SI],chip_8250  ; 8250?
  15.         JE      serint_qrqp_not     ;      Yep....
  16.  
  17. ;--------------------------------------------------------------------------;
  18. ; This outside loop is for the QuadPort board or the 4 async port          ;
  19. ; card.  We loop thru all the ports checking for pending interrupts        ;
  20. ; and handling them.  There is a catch at the far end which loops us       ;
  21. ; back.  Other than that, there are no changes.                            ;
  22. ;                                                                          ;
  23. ; The only difference between the QUADRAN QUADPORT card and the 4 async    ;
  24. ; port card is that the QuadPort card has an extra register for interrupt  ;
  25. ; control.                                                                 ;
  26. ;--------------------------------------------------------------------------;
  27.  
  28.         CMP     chip[SI],chip_qrqp  ; Quadram QuadPort?
  29.         JNE     serint_qrqp_do      ;     Nope.. go directly to loop.
  30.                                     ;     This happens for the 4 async port
  31.  
  32. ;--------------------------------------------------------------------------;
  33. ; Get the Master Interrupt ID register....  If nothing to do then quit     ;
  34. ;--------------------------------------------------------------------------;
  35.  
  36.         AND     DL,basem_qrqp       ; Now get the board base address
  37.         ADD     DX,qintr_qrpt       ; Point to master interrupt register
  38.         IN      AL,DX               ;      and read it...
  39.         AND     AL,00011111B        ; Remove unnecessary bits
  40. ;       JNZ     serint_qrqp_do      ;     We have something to do
  41. ;       JMP     serint_qrqp_gobye   ;     Nothing here!  Leave...
  42.  
  43. serint_qrqp_do:
  44.  
  45. ;--------------------------------------------------------------------------;
  46. ; Get ready to loop                                                        ;
  47. ;--------------------------------------------------------------------------;
  48.  
  49.         MOV     qrqp_tie_pointer,0  ; Pointer to tie pointer to service next
  50.  
  51. ;--------------------------------------------------------------------------;
  52. ; Here is the loop... AL contains the MIR and SI points to one of the      ;
  53. ; com blocks to get here                                                   ;
  54. ;--------------------------------------------------------------------------;
  55.  
  56. serint_qrqp_loop:
  57.  
  58.         MOV     DI,chip_comm[SI]    ; Where is the tie block?
  59.         MOV     CX,qrqp_tie_pointer ; Pointer to tie pointer to service next
  60.  
  61.         CMP     chip[SI],chip_qrqp  ; Quadram QuadPort?
  62.         JNE     serint_qrqp_more    ;      Nope.. keep going....
  63.  
  64.         CMP     CX,max_port_qrqp*2  ; Are we at the end?
  65.         JL      serint_qrqp_more    ;      Nope.. keep going....
  66.         JMP     serint_qrqp_exit    ;      Yep... Time to go
  67.  
  68. serint_qrqp_more:
  69.  
  70. ;--------------------------------------------------------------------------;
  71. ; Now we increment the pointer for the next time thru (if any)             ;
  72. ;--------------------------------------------------------------------------;
  73.  
  74.         ADD     DI,CX               ; Add the offset so we can find the block
  75.         INC     CX                  ; Bump the pointer to the next ptr in tie
  76.         INC     CX                  ;      block (2 for words)
  77.         MOV     qrqp_tie_pointer,CX ; Save pointer for next time around
  78.  
  79. ;--------------------------------------------------------------------------;
  80. ; Fetch the comm block address.  If it exists, we continue normally        ;
  81. ; If not, then:                                                            ;
  82. ;   1) On a QUADRAM QUADPORT card, this is not our channel.  We skip it    ;
  83. ;      and go to the next one.  The order in the tie block is important    ;
  84. ;      because the entries are in the same order as the master interrupt   ;
  85. ;      register                                                            ;
  86. ;   2) On a 4 async port card, this signifies the end of the list.         ;
  87. ;--------------------------------------------------------------------------;
  88.  
  89.         MOV     CX,WORD PTR [DI]    ; Get the comm block
  90.         OR      CX,CX               ; Is there one?
  91.         JNZ     serint_qrqp_okblock ;      Yep.. Lets do it
  92.  
  93.         CMP     chip[SI],chip_qrqp  ; Quadram QuadPort?
  94.         JE      serint_qrqp_loop    ;      Yep.. Loop again to ignore this port
  95.  
  96.         JMP     serint_4apc_exit    ; 4 async port card exit
  97.  
  98. serint_qrqp_okblock:
  99.  
  100.         MOV     SI,CX               ; Put the address in the right place
  101.  
  102. ;--------------------------------------------------------------------------;
  103. ; See if this is the QuadPort card and, therefore, contains a master       ;
  104. ; interrupt register to check.  If not, keep going....                     ;
  105. ;--------------------------------------------------------------------------;
  106.  
  107.         CMP     chip[SI],chip_qrqp  ; Quadram QuadPort?
  108.         JNE     serint_4apc_do      ;     Nope.. go directly to loop.
  109.  
  110. ;--------------------------------------------------------------------------;
  111. ; Each bit in the MIR corresponds to one chip on the board so we will      ;
  112. ; see if the chip whose com block I am looking at wants service            ;
  113. ;--------------------------------------------------------------------------;
  114.  
  115.         SHR     AL,1                ; Shift the MIR one right putting the low
  116.                                     ; order bit it the carry register
  117. ;       JNB     serint_qrqp_loop    ; Carry bit is off, this chip does not
  118.                                     ;      want to be serviced...
  119.  
  120. ; This use to be below the label
  121.         MOV     qrqp_save_mir,AL    ; Save the shifted master interrupt register
  122.  
  123. ;--------------------------------------------------------------------------;
  124. ; We now have a port who wants something.  We now set the registers as     ;
  125. ; if this is a regular 8250 and let the normal interrupt handler           ;
  126. ; do its work.                                                             ;
  127. ;--------------------------------------------------------------------------;
  128.  
  129. serint_4apc_do:
  130.  
  131.         MOV     serint_4apc_switch,0 ; Clear the interrupt handled switch
  132.  
  133.         MOV     DX,baseaddr[SI]     ; Get the base port address
  134.  
  135. ; End QuadRam QuadPort board handler start
  136.  
  137. serint_qrqp_not:                    ; Used for real 8250s to skip everything
  138.  
  139.   ENDIF
  140.  
  141.         MOV     CX,DX               ; Save the port address
  142.  
  143. ;--------------------------------------------------------------------------;
  144. ; Get the IIR to identify the cause                                        ;
  145. ;--------------------------------------------------------------------------;
  146.  
  147.         ADD     DX,iir_8250         ; Get the IIR
  148.         IN      AL,DX               ;
  149.  
  150. ;--------------------------------------------------------------------------;
  151. ; If no interrupt pending on this channel, skip it.                        ;
  152. ;--------------------------------------------------------------------------;
  153.  
  154.         AND     AL,iir_8250_ip      ; Interrupt pending?
  155. ; V3.2 attempts un-nooped the next two instructions
  156.         JZ      serint_8250_do      ;     Yep...
  157.         JMP     serint_8250_exit    ;     No leave...
  158.  
  159. ;==========================================================================;
  160. ; This is the place we come to when we want to service the chip            ;
  161. ;==========================================================================;
  162.  
  163. serint_8250_do:
  164.  
  165. ;--------------------------------------------------------------------------;
  166. ; Get the LSR                                                              ;
  167. ;--------------------------------------------------------------------------;
  168.  
  169.         MOV     DX,CX               ; Get the LSR
  170.         ADD     DX,lsr_8250         ;
  171.         IN      AL,DX               ;
  172.  
  173. ;==========================================================================;
  174. ; This label is used when the LSR is already loaded                        ;
  175. ;==========================================================================;
  176.  
  177. serint_8250_int_loop:
  178.  
  179. ;--------------------------------------------------------------------------;
  180. ; Save the LSR by oring into the status block                              ;
  181. ;--------------------------------------------------------------------------;
  182.  
  183.         AND     last_rs[SI],0FFH-lsr_8250_thre ; Remove THRE
  184.         OR      last_rs[SI],AL      ; And tuck it away
  185.  
  186. ;==========================================================================;
  187. ; Receive Data Available handler                                           ;
  188. ;==========================================================================;
  189.  
  190.         TEST    AL,lsr_8250_dr      ; RDA on?
  191.         JZ      serint_8250_norda   ;      No receive data available
  192.  
  193.   IF present_4apc
  194.         MOV     serint_4apc_switch,1 ; Set the interrupt handled switch
  195.   ENDIF
  196.  
  197. ;--------------------------------------------------------------------------;
  198. ; Get the data                                                             ;
  199. ;--------------------------------------------------------------------------;
  200.  
  201.         MOV     DX,CX               ; Get the RBR
  202. ;       ADD     DX,rbr_8250         ;     This is zero so we don't do it...
  203.         IN      AL,DX               ;
  204.  
  205. ;--------------------------------------------------------------------------;
  206. ; Take the data we just got and stuff it into the buffer                   ;
  207. ;--------------------------------------------------------------------------;
  208.  
  209.         MOV     DI,buffer_r_in[SI]  ; Get the buffer pointer
  210.         MOV     DX,ES               ; Gotta use ES so save it
  211.         MOV     ES,buffer_r_a[SI]   ; Get buffer's segment
  212.         MOV     ES:[DI],AL          ; Save the character
  213.         MOV     ES,DX               ; All done with ES so put it back
  214.  
  215. ;--------------------------------------------------------------------------;
  216. ; Bump pointer and handle wrapping around the end of the buffer            ;
  217. ;--------------------------------------------------------------------------;
  218.  
  219.         INC     DI                  ; Bump pointer and handle wrap
  220.         CMP     DI,buffer_size      ;
  221.         JL      serint_8250_nowrap  ;
  222.         SUB     DI,DI               ;
  223. serint_8250_nowrap:
  224.  
  225. ;--------------------------------------------------------------------------;
  226. ; See if we are about try to store into a buffer position that hasn't      ;
  227. ; been emptied yet.  If this occurs, don't bump the pointer but signal     ;
  228. ; overflow instead                                                         ;
  229. ;--------------------------------------------------------------------------;
  230.  
  231.         CMP     DI,buffer_r_out[SI] ; Overflow of buffer?
  232.         JNE     serint_8250_noover  ;
  233.         OR      last_rs[SI],lsr_8250_or ; Overrun indicate
  234.         JMP     SHORT serint_8250_over ;  Don't save the updated pointer
  235. serint_8250_noover:
  236.         MOV     buffer_r_in[SI],DI  ; Save the updated pointer
  237. serint_8250_over:
  238.  
  239. ;--------------------------------------------------------------------------;
  240. ; If we have hardware handshaking enabled, then see if we need to          ;
  241. ; signal stop.  We will use 1/16 of a buffer as a limit                    ;
  242. ;--------------------------------------------------------------------------;
  243.  
  244.         TEST    options[SI],opt_hdwhs ; Hardware handshaking desired?
  245.         JZ      serint_8250_r_nostop  ;      Nope
  246.  
  247.         SUB     DI,buffer_r_out[SI] ; Compute the delta
  248.         JG      serint_8250_rpos    ;     Jump over if positive result
  249.         ADD     DI,buffer_size      ; This will convert it back to positive
  250. serint_8250_rpos:                   ; DI now is equal to bytes used!
  251.  
  252.         CMP     DI,(buffer_size * 15) / 16   ; See if at least 1/16 is left
  253.         JLE     serint_8250_r_nostop ;             Yes.. No stop needed
  254.  
  255.         MOV     DX,CX               ; Get the MCR
  256.         ADD     DX,mcr_8250         ;
  257.         MOV     AL,hoff_8250        ; Turn off sending from distant end
  258.         OUT     DX,AL               ;
  259.  
  260. serint_8250_r_nostop:
  261.  
  262. ;--------------------------------------------------------------------------;
  263. ; Finished with receive data interrupt                                     ;
  264. ;--------------------------------------------------------------------------;
  265.  
  266. serint_8250_norda:                  ; No receive data available
  267.  
  268. ;==========================================================================;
  269. ; Transmit Holding Buffer Empty handler                                    ;
  270. ;==========================================================================;
  271.  
  272. ;--------------------------------------------------------------------------;
  273. ; Read the MSR.. We always do this to clear any pending modem status       ;
  274. ; change interrupt                                                         ;
  275. ;--------------------------------------------------------------------------;
  276.  
  277.         MOV     DX,CX               ; Compute port address for the MSR
  278.         ADD     DX,msr_8250         ;
  279.         IN      AL,DX               ; Get the MSR into AL
  280.  
  281. ;--------------------------------------------------------------------------;
  282. ; Now look at the THRE.  If its not on, ignore all of this                 ;
  283. ;--------------------------------------------------------------------------;
  284.  
  285.         TEST    last_rs[SI],lsr_8250_thre ; Transmit holding register empty ?
  286.         JZ      serint_8250_nothre  ;           Nope
  287.  
  288. ;--------------------------------------------------------------------------;
  289. ; See if anything to be sent.  Note...  If transmit buffering is not       ;
  290. ; selected for this channel, this will never be true.  Save us from        ;
  291. ; having to check the options field                                        ;
  292. ;--------------------------------------------------------------------------;
  293.  
  294.         MOV     DI,buffer_t_out[SI] ; Get buffer output pointer
  295.         CMP     DI,buffer_t_in[SI]  ; See where the in pointer is
  296.         JE      serint_8250_nothre  ; If they are not equal then we have
  297.                                     ; data in the buffer
  298.  
  299. ;--------------------------------------------------------------------------;
  300. ; Worry about hardware handshaking as appropriate.                         ;
  301. ;--------------------------------------------------------------------------;
  302.  
  303.         TEST    options[SI],opt_hdwhs ; Hardware handshaking desired?
  304.         JZ      serint_8250_thre_nohw ;     Nope..
  305.  
  306.                                     ; Check the previously loaded MSR
  307.         AND     AL,msr_8250_cts     ; CTS on?
  308.         JNZ     serint_8250_thre_nohw ;     Yep, send something
  309.  
  310.         OR      flags[SI],flags_xmt_h ; Show transmitter is held
  311.         JMP     serint_8250_nothre  ;   Don't do anything else
  312.  
  313. serint_8250_thre_nohw:
  314.  
  315. ;--------------------------------------------------------------------------;
  316. ; Ok we have something to send and all the indicators are go!!!            ;
  317. ;--------------------------------------------------------------------------;
  318.  
  319.         AND     flags[SI],0FFH-flags_xmt_h ; Remove transmitter held flag
  320.  
  321.         MOV     DX,ES               ; Gotta use ES so save it
  322.         MOV     ES,buffer_t_a[SI]   ; Get buffer's segment
  323.         MOV     AL,ES:[DI]          ; Save the character
  324.         MOV     ES,DX               ; All done with ES so put it back
  325.  
  326.         MOV     DX,CX               ; Compute port address for the THR
  327. ;       ADD     DX,thr_8250         ;      and then
  328.         OUT     DX,AL               ;      out the character
  329. ; The add of THR is commented out since the THR is at zero from
  330. ; the base.  This just documents the fact we are going for the THR
  331.  
  332. ;--------------------------------------------------------------------------;
  333. ; Turn on the character sent flag                                          ;
  334. ;--------------------------------------------------------------------------;
  335.  
  336.         OR      flags[SI],flags_xmt_on ; Turn on transmitter flag
  337.  
  338. ;--------------------------------------------------------------------------;
  339. ; Bump pointer and handler wrap condition                                  ;
  340. ;--------------------------------------------------------------------------;
  341.  
  342.         INC     DI                  ; Bump pointer and handle wrap
  343.         CMP     DI,buffer_size      ;
  344.         JL      serint_8250_nothrewrap ;
  345.         SUB     DI,DI               ;
  346. serint_8250_nothrewrap:
  347.  
  348.         MOV     buffer_t_out[SI],DI ; Save buffer output pointer
  349.  
  350. ;--------------------------------------------------------------------------;
  351. ; Finished with transmit holding buffer empty interrupt                    ;
  352. ;--------------------------------------------------------------------------;
  353.  
  354.   IF present_4apc
  355.         MOV     serint_4apc_switch,1 ; Set the interrupt handled switch
  356.   ENDIF
  357.  
  358. serint_8250_nothre:
  359.  
  360. ;==========================================================================;
  361. ; Exit interrupt handler when we have done something                       ;
  362. ;==========================================================================;
  363.  
  364.         MOV     AL,pic_clear        ; Tell 8259 we are done
  365.  
  366.         TEST    options[SI],opt_high_irq ; Slave 8259 involved?
  367.         JZ      serint_8250_pic_master   ; Nope
  368.  
  369.         OUT     pic2_cmd_port,AL    ; Clear slave
  370.  
  371. serint_8250_pic_master:
  372.  
  373.         OUT     pic_cmd_port,AL     ; Clear master
  374.  
  375. ;--------------------------------------------------------------------------;
  376. ; If interrupt pending on this channel still, go back and do it            ;
  377. ;--------------------------------------------------------------------------;
  378.  
  379.         MOV     DX,CX               ;
  380.         ADD     DX,iir_8250         ; Get the IIR
  381.         IN      AL,DX               ;
  382.  
  383.         AND     AL,iir_8250_ip      ; Interrupt pending?
  384.         JNZ     serint_8250_noip    ;     Nope..   Go to common exit routine
  385.  
  386.   IF present_4apc
  387.         MOV     serint_4apc_switch,1 ; Set the interrupt handled switch
  388.   ENDIF
  389.  
  390.         JMP     serint_8250_do      ;     Yep...   Loop back
  391.  
  392. serint_8250_noip:
  393.  
  394. ;==========================================================================;
  395. ; Exit Interrupt handler                                                   ;
  396. ;==========================================================================;
  397.  
  398. serint_8250_exit:
  399.  
  400.   IF present_qrqp OR present_4apc
  401.  
  402.         CMP     chip[SI],chip_8250  ; Plain old 8250?
  403.         JE      serint_qrqp_gobye   ;      Yep.....
  404.  
  405.         CMP     chip[SI],chip_4apc  ; Four Async port card
  406.         JNE     serint_qrqp_byechk  ;      Nope... Must be quadram
  407.  
  408. ;--------------------------------------------------------------------------;
  409. ; This is the end of interrupt handler for the 4 async port card           ;
  410. ; It works on the premise that if we handled any interrupts we will        ;
  411. ; have to repoll everyone to ensure that at some instant, all the          ;
  412. ; interrupts were cleared.  We do this by forcing the pointer to the       ;
  413. ; port under test back to the beginning of the list                        ;
  414. ;--------------------------------------------------------------------------;
  415.  
  416.  
  417.         CMP     serint_4apc_switch,0 ; Set the interrupt handled switch
  418.         JE      serint_4apc_noint   ;
  419.  
  420.         MOV     qrqp_tie_pointer,0  ; Pointer to tie pointer to service next
  421.  
  422. serint_4apc_noint:
  423.  
  424.         JMP     serint_qrqp_loop    ; Loop
  425.  
  426. ;--------------------------------------------------------------------------;
  427. ; This is the end of interrupt handler for the QUADRAM QuadPort card       ;
  428. ;--------------------------------------------------------------------------;
  429.  
  430. serint_qrqp_byechk:
  431.  
  432. ;--------------------------------------------------------------------------;
  433. ; This code loops back to the top of the interrupt handler if this is      ;
  434. ; a QuadRam Quadport board with more to do                                 ;
  435. ;--------------------------------------------------------------------------;
  436.  
  437.         CMP     chip[SI],chip_qrqp  ; QUADRAM QUADPORT card?
  438.         JNE     serint_qrqp_goback  ;      Nope....  Force return
  439.  
  440.         MOV     AL,qrqp_save_mir    ; Get the shifted master interrupt register
  441.         OR      AL,AL               ; Anything left to do?
  442.         JZ      serint_qrqp_exit    ;      Nope....
  443. serint_qrqp_goback:
  444.         JMP     serint_qrqp_loop    ;      Yep.....
  445.  
  446. ;--------------------------------------------------------------------------;
  447. ; QUADRAM QuadPort card exit routine                                       ;
  448. ;--------------------------------------------------------------------------;
  449.  
  450. serint_qrqp_exit:
  451.  
  452. ;--------------------------------------------------------------------------;
  453. ; Clear the master interrupt register                                      ;
  454. ;--------------------------------------------------------------------------;
  455.  
  456.         MOV     DX,baseaddr[SI]     ; Get the base port address
  457.         AND     DL,basem_qrqp       ; Now get the board base address
  458.         ADD     DX,qintr_qrpt       ; Point to master interrupt register
  459.  
  460.         MOV     AL,hiv[SI]          ; Get the hardware interrupt vector number
  461.  
  462.         CMP     AL,irq2_offset      ; Convert it to IRQ number
  463.         JL      serint_qrqp_exit2   ;
  464.         SUB     AL,irq2_offset-8    ;
  465.         JMP     SHORT serint_qrqp_exit3;
  466. serint_qrqp_exit2:
  467.         SUB     AL,irq_offset       ;
  468. serint_qrqp_exit3:
  469.  
  470.         CBW                         ;
  471.         MOV     DI,AX               ; Make into an index
  472.         MOV     AL,qrqp_int_map[DI] ; Get the proper setting for the vector
  473.         OUT     DX,AL               ; And send it
  474.  
  475. ;--------------------------------------------------------------------------;
  476. ; See if there is anything left to do                                      ;
  477. ;--------------------------------------------------------------------------;
  478.  
  479.         IN      AL,DX               ;      and read it...
  480.         AND     AL,00011111B        ; Remove unnecessary bits
  481.         JZ      serint_qrqp_gobye   ;     We have nothing to do
  482.         JMP     serint_qrqp_do      ;     We have something to do
  483.  
  484. serint_qrqp_gobye:
  485.  
  486.   ENDIF
  487.  
  488. ;--------------------------------------------------------------------------;
  489. ; We come here when all the interrupts are clear on a 4 async port card    ;
  490. ;--------------------------------------------------------------------------;
  491.  
  492. serint_4apc_exit:
  493.  
  494. ;--------------------------------------------------------------------------;
  495. ; Clear the system interrupt!                                              ;
  496. ;--------------------------------------------------------------------------;
  497.  
  498.         JMP     serint_exit         ; Go to common exit routine
  499.  
  500.